/*********************************************************************************************************************
 * jQuery Plugin
 * 
 * DESCRIZIONE DEL PLUGIN:
 * Al momento la photogallery permette esclusivamente di aggiungere le immagini e gli album attraverso
 * il metodo ajax, sfruttando uno script PHP che restituisce un array tramite <b><i>json_encode()</i></b>
 * L'array deve essere del tipo myarray = array('photo' => array(), 'albums' => array())
 * 
 * FUNZIONALITA' DEL PLUGIN:
 * Questo plugin permette di mandare avanti e indietro le foto (tramite appositi pulsanti o tramite tastiera),
 * di eseguire la foto gallery in autoplay e di mettere in pause/play la stess (tramite apposito pulsante), inoltre
 * è anche visibile una thumbnail e l'elenco degli album fotografici.
 * E' possibile selezionare le foto direttamente dalla thumbnail.
 * Inoltre le barre della thumbnail, degli album e quella dei comandi scompaiono e riappaiono solo col muoversi del
 * mouse.
 * All'ultente è anche data la possibilità di far vedere la fotogallery quanto la finestra del browser o stbilendo 
 * delle dimensioni personali.
 * 
 * SUPPORTATO DA:
 *      - Webkit browser (Chrome, Safari)
 *      - 
 * 
 * @name    Super PhotoGallery
 * @version 1.0
 * @author  Mattia Leonardo Angelillo
 * @email   mattia.angelillo@gmail.com
 * @license 
**********************************************************************************************************************/


(function($) {
    $.fn.photo_gallery = function(options) {
        // valori di default
        var config = {
            /**
             * Indica il tipo per reperire le immagini.
             * I valori possibili sono:
             * - ajax Se le immagini sono prese da una cartella
             */
            type : 'ajax',
            /**
             * URL della pagina da dove prelevare le immagini.
             * N.B.: Il file deve ritornare un tipo JSON
             */
            url : 'return.php',
            /**
             * Dato o dati da passare all'url se il tipo di richiesta è Ajax
             */
            data : {'photo':'', 'albums':''},
            /**
             * Percorso della cartella dove trovare le imagini se il tipo di richiesta è ajax
             */
            route : {
                'photodir'  : '',
                'albumsdir' : '',
                'coversdir' : ''
            },
            /**
             * Tipo di css da applicare alla foto gallery.
             * N.B.: Il CSS di default è <b>fullscreen</b>
             */
            css   : 'fullscreen',
            /**
             * Autoplay.
             * Definisce se la foto gallery deve essere eseguita in autoplay
             * Assume i valori true o false
             */
            autoplay : true,
            /**
             * Oggetto contenente il percorso dei pulsanti del file
             */
            pushbutton : {'play': '', 'pause' : '', 'prev' : '', 'next' : ''},
            /**
             * Se impostato a true regola la compatibilità per i dispositivi mobili.
             * Di default è impostato a true
             */
            mobile : true
        };
        
        if (options) $.extend(config, options);
        
        //Elenco degli effetti
        var effects = Array(
                            'Blind',
                            'Bounce',
                            'Clip',
                            'Drop',
                            'Explode',
                            'Fold',
                            'Highlight',
                            'Puff',
                            'Pulsate',
                            'Scale',
                            'Shake',
                            'Size',
                            'Slide'
                        );
        
        var id = "sm_gallery";//Identificatore della foto gallery
        /**
         * Array per costruire la coda delle immagini
         */
        var queue_photo = new Array();
        /**
         * Array per costruire la coda degli album
         */
        var queue_albums = new Array();
        /**
         * Array per costuire la coda delle cover degli album
         */
        var queue_covers = new Array();
        /**
         * Variabili passate da url e messe in in oggetto
         */
        var $_GET = {};
        /**
         * Recupero le varibili passate tramite URL e le metto in $_GET['nome'] = 'valore'
         */
        document.location.search.replace(/\??(?:([^=]+)=([^&]*)&?)/g, function () {
            function decode(s) {
                return decodeURIComponent(s.split("+").join(" "));
            }

            $_GET[decode(arguments[1])] = decode(arguments[2]);
        });        
        /**
         * Variabile che definisce play o pause
         */
        var playpause = (options.autoplay == true) ? (options.pushbutton['pause']) : (options.pushbutton['play']);
        /**
         * User agents per determinare il tipo di browser (Desktop o Mobile=
         */
        $.browser.device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
        /**
         * Larghezza finestra browser
         */
        var browser_screen_width  = $(window).width();
        /**
         * Altezza finestra browser
         */
        var browser_screen_height = $(window).height();
        
        
        
        
        
        //Immagini passate tramite Ajax
        if(options.type === "ajax"){
            var url  = options.url;
            var data = "";
            
            //Controllo se ho caricato un nuovo album
            if($_GET['load'] == 'true'){
                data = "dir="+options.route.albumsdir+$_GET['album']+"/&albums="+options.route.albumsdir;
                
                if($_GET['album']){
                    //options.route.albumdir = $_GET['album']+"/";
                    options.route.photodir = options.route.albumsdir+$_GET['album']+"/";
                }
            }else{
                //url  = options.url;
                data = options.data;
            }
            
            //Ajax per richiesta immagini
            $.ajax({
                url         : url,     //URL
                data        : data,    //Dati da passare tramite ajax
                dataType    : 'json',  //Riceve un dato JSON
                async       : false,   //Eseguo ajax in modalità asincrona, cioè nell'ordine in cui è stato dichiarato
                
                //Funzioni di ritorno dei dati
                success : function (righe,stato) {
                    //Photoes
                    for (i=0; i < righe['photo'].length; i++) {
                        queue_photo[i] = righe['photo'][i];
                    }
                    //Albums
                    $.each(righe['albums']['name'], function (i, item){
                        queue_albums[i] = righe['albums']['name'][i];
                        queue_covers[i] = righe['albums']['cover'][i];
                    });
                },
                error : function(jqXHR, textStatus, errorThrown) {
                    alert("Error... " + textStatus + "        " + errorThrown);
                },
                complete : function (data){
                }
            });//Fine richiesta Ajax
        }
        
        /*============================================
         * STRUTTURA DELLA FOTO GALLERY
         ===========================================*/
        var element = "<div id=\""+id+"\">\n"+
                            "<div class='albums'>"+
                                //Qui andranno messi gli album
                            "</div>"+
                            "<div class=\"container\">\n"+
                                //Pulsantiera
                                "<div class=\"pushbutton\">\n"+
                                        "<div class=\"prev\">\n"+
                                            "<img src=\""+options.pushbutton['prev']+"\" />"+
                                        "</div>\n"+
                                        "<div class=\"playpause\">\n"+
                                            //playpause +
                                            "<img src=\""+playpause+"\" />"+
                                        "</div>\n"+
                                        "<div class=\"next\">\n"+
                                            "<img src=\""+options.pushbutton['next']+"\" />"+
                                        "</div>\n"+
                                "</div>\n"+
                                
                                "<div class=\"photo container\">\n"+
                                    //Qui includo le immagini
                                "</div>\n"+
                                
                                "<div class=\"thumbnail\">\n"+
                                    //Qui inserisco le anteprime della thumbnail
                                "</div>\n"+
                            "</div>\n"+
                       "</div>\n";
        //FINE STRUTTURA DELLA FOTO GALLERY
        
        //Rimpiazzo il contenitore selezionato dal plugin con la foto gallery
        $(this).replaceWith(element);
        
        /*===============================
         * AGGIUNTA DELLE IMMAGINI
         ==============================*/
        for (i=0;i<queue_photo.length;i ++){
            $(".container .photo.container", "#"+id)
                    .append("<div class=\"img "+i+"\">"+
                                "<img src=\""+
                                    options.route.photodir+queue_photo[i]+
                                    "\" />"+
                            "</div>");
            
            //Thumbnail
            $(".container .thumbnail", "#"+id)
                    .append("<div class=\"img normal "+i+"\">"+
                                "<img src=\""+
                                    options.route.photodir+queue_photo[i]+
                                    "\" />"+
                            "</div>");
        }
        $(".container .photo.container .img:first-child").addClass("show");
        //FINE AGGIUNTA DELLE IMMAGINI
        
        /*=============================
         * AGGIUNTA DEGLI ALBUM
         ============================*/
        for(i=0;i<queue_albums.length;i ++){
            $(".albums", "#"+id)
                    .append("<div class=\"img "+i+"\">"+
                                "<a href=\""+document.location.pathname+"?load=true&album="+queue_albums[i]+"\"><img src=\""+
                                    options.route.albumsdir+queue_albums[i]+"/cover/"+queue_covers[i]+
                                    "\" /></a>"+
                            "</div>");
        }
        
        /*********************
         * AUTOPLAY
         ********************/
        if(options.autoplay === true){
            /*playpause = options.pushbutton['pause'];
            alert(playpause);*/
            autoplay();
        }
        
        //Elementi della thumbnail
        var dom_thumbnail_img = $(".thumbnail .img", "#"+id);
        
        //Setto l'elemento selezionato, di default
        $(".thumbnail .img:first-child", "#"+id).removeClass("normal").attr("class", $(".thumbnail .img", "#"+id).attr("class") + " this");
 
        /*==================================
         * CSS COMUNI A TUTTI GLI STILI
         =================================*/
        $(".this", "#"+id).css({
            'box-shadow' : '0px 0px 50px green inset',
            '-webkit-box-shadow' : '0px 0px 50px green inset',
            '-moz-box-shadow' : '0px 0px 50px green inset'
        });
        $(".normal", "#"+id).css({
            'box-shadow' : '0px 0px 50px red inset',
            '-webkit-box-shadow' : '0px 0px 50px red inset',
            '-moz-box-shadow' : '0px 0px 50px red inset'
        });
        var browser_screen_width  = $(window).width();  //Larghezza del browser
        var browser_screen_height = $(window).height(); //Altezza del browser
        var thumbnail_height;                           //Altezza della thumbnail

        $("html, body, body *").css({
            'margin'  : 0,
            'padding' : 0
        });
        
        //ALBUMS
        $(".albums", "#"+id).css({
            'height'     : '50px',
            'background' : 'rgba(255, 200, 200, .4)'
        });
        $(".albums .img", "#"+id).css({
            'border'     : '1px solid',
            'height'     : '50px',
            'width'      : '50px',
            'display'    : 'inline-block',
            'margin-right'  : '5px',
            'background' : 'rgba(255, 200, 200, .4)'
        });
        $(".albums .img img", "#"+id).css({
            'height'        : '50px',
            'width'         : '50px',
            'display'       : 'inline-block',
            'background'    : 'rgba(255, 200, 200, .4)'
        });
        
        //PUSHBUTTON
        $(".pushbutton", "#"+id).css({
            'border'        : '1px solid',
            'background'    : 'rgba(0, 0, 0, .6)',
            'width'         : '150px',
            'height'        : '50px',

            'border-radius'         : '250px',
            '-moz-border-radius'    : '250px',
            '-webkit-border-radius' : '250px'
        });
        $(".pushbutton .prev, .pushbutton .next, .pushbutton .playpause", "#"+id).css({
            'float'     : 'left',
            'border'    : '0px solid',
            'width'     : '50px',
            'height'    : '50px',
        });
        $(".pushbutton .prev img, .pushbutton .next img, .pushbutton .playpause img", "#"+id).css({
            'width'     : '50px',
            'height'    : '50px',
        });

        //THUMBNAIL
        $(".container .thumbnail", "#"+id).css({
            'padding'       : '5px',
            'border'        : '1px solid',
            'height'        : '50px',
            'background'    : '#fff',

            //Ombra
            'box-shadow'    : '0px 0px 12px darkred inset,\n\
                                -15px 0px 15px darkred inset',
            '-moz-box-shadow'    : '0px 0px 12px darkred inset,\n\
                                -15px 0px 15px darkred inset',
            '-webkit-box-shadow'    : '0px 0px 12px darkred inset,\n\
                                -15px 0px 15px darkred inset'
        });
        $(".container .thumbnail .img", "#"+id).css({
            'float'  : 'left',
            'width'  : '50px',
            'height' : '50px'
        });
        $(".container .thumbnail .img img", "#"+id).css({
            'border'        : '1px solid',
            'width'         : '50px',
            'height'        : '50px',
            'margin-right'  : '5px',

            //Ombra esterna
            'box-shadow'            : '0px 0px 10px #000',
            '-moz-box-shadow'       : '0px 0px 10px #000',
            '-webkit-box-shadow'    : '0px 0px 10px #000',
        });

        thumbnail_height = $(".container .thumbnail", "#"+id).height();
        
        //IMMAGINI
        $(".container .photo.container", "#"+id).css({
            'border'    : '0px solid red',
            'background': 'red',
            'position'  : 'fixed',
            'overflow'  : 'hidden',
            'width'     : browser_screen_width+"px",
            'height'    : (browser_screen_height)+"px"
        });//?
        $(".container .photo.container .img", "#"+id).css({
            'display'       : 'none',
            'background'    : 'rgba(0, 0, 0, .8)'
        });
        $(".container .photo.container .img:first-child", "#"+id).css({
            'display' : 'block'
        });
        $(".container .photo.container .img img", "#"+id).css({
            'display' : 'block',
            'margin'  : '0 auto',
            'height'    : (browser_screen_height)+"px"
        });
        
        /*==============================================
         * CSS PER I DISPOSITIVI MOBILI
        ==============================================*/
        if(options.mobile == true){
            $.browser.device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
            
            if($.browser.device){//Dispositivo mobile
                
            }
        }
        //FINE
        
        
        /*==============================================
         * APPLICAZIONE DEL CSS SCELTO
         =============================================*/
        if(options.css === "fullscreen"){
            fullscreen();
        }
        //FINE
        
        
        //if(!$.browser.device){
        /*=====================================
         * EVENTI
        ======================================*/
        /*#################
         # THUMBNAIL      #
         ################*/
        //Fadeoutmousemove
        if((!options.mobile && $.browser.device) || (browser_screen_width >= 1024 && browser_screen_width <= 1920)){
            $(".thumbnail", "#"+id).fadeOut(5000);
            $(".container .photo.container", "#"+id).on({
                mousemove : function (){
                    if($(".thumbnail", "#"+id).is(":hidden") === true){
                        $(".thumbnail", "#"+id).fadeIn(500);
                        $(".thumbnail", "#"+id).stop().fadeTo(1, 1).fadeOut(10000); 
                    }
                },
                mousestop : function (){
                    if($(".thumbnail", "#"+id).is(":visible") || $(".albums", "#"+id).is(":visible") || $(".pushbutton", "#"+id).is(":visible")){
                        $(".thumbnail", "#"+id).fadeOut(5000);
                        $(".albums", "#"+id).fadeOut(5000);
                        $(".pushbutton", "#"+id).fadeOut(5000);
                    }
                }
            });
            //Se è un dispositivo mobile
            if(options.mobile && $.browser.device){
                $(".container .photo.container", "#"+id).click(function (){
                    if($(".thumbnail", "#"+id).is(":hidden") === true){
                        $(".thumbnail", "#"+id).fadeIn(500);
                        $(".thumbnail", "#"+id).stop().fadeTo(1, 1).fadeOut(10000); 
                    }
                });
            }
            $(".thumbnail", "#"+id).on({
                mouseenter : function (){
                    $(this).stop().fadeTo(1, 1);
                },
                mouseout : function (){
                    $(this).fadeOut(5000);
                }
            });

            //Click sull'immagine della thumbnail da visualizzare
            $(".thumbnail .img").click(function (){
                var offset = $(this).offset();
                //Posizione dell'elemento nel DOM
                //var position = $(this).position();
                var pos = 0;

                for (i=0;i<dom_thumbnail_img.length;i ++){
                    if(($(dom_thumbnail_img[i]).offset().left == offset.left) && ($(dom_thumbnail_img[i]).offset().top == offset.top)){
                        pos = i+1;

                        break;
                    }
                }

                image_pos = pos;//Posizione della nuova immagina da visualizzare

                //Rimuovo this
                $(".thumbnail .this", "#"+id).removeClass("this");
                //Agiungo this all'elemento cliccato
                $(this).addClass("this");

                //Visualizzo l'immagine cliccata
                $(".photo .img img", "#"+id).fadeOut(500);
                $(".photo .img:nth-child("+pos+")", "#"+id).fadeIn(900);
            });
        }
        /*##########################
         # PULSANTIERA             #
         ##########################*/
        if(options.mobile == false || $.browser.device == false){
            //PUSHBUTTON
            $(".pushbutton", "#"+id).fadeOut(5000);
            $(".container .photo.container", "#"+id).mousemove(function (){
                if($(".pushbutton", "#"+id).is(":hidden") === true){
                    $(".pushbutton", "#"+id).fadeIn(500);
                    $(".pushbutton", "#"+id).stop().fadeTo(1, 1).fadeOut(10000); 
                }
            });
            $(".pushbutton", "#"+id).on({
                mouseover  : function (){
                    //alert("OVER");
                    $(this).stop().fadeTo(1, 1);
                },
                mouseenter : function (){
                    //alert("ENTER");
                    $(this).stop().fadeTo(1, 1);
                },
                mouseout : function (){
                    //alert("OUT");
                    $(this).fadeOut(5000);
                }
            });
        }
        //PREV
        $(".pushbutton .prev", "#"+id).click(function (){
            prev();
        });
        //NEXT
        $(".pushbutton .next", "#"+id).click(function (){
            next();
        });
        //PLAY/PAUSE
        $(".pushbutton .playpause", "#"+id).click(function (){
            playorpause();
        });


        /*###############################
         # ALBUMS                       #
         ##############################*/
        if((!options.mobile && $.browser.device) || (browser_screen_width >= 1024 && browser_screen_width <= 1920)){
            $(".albums", "#"+id).fadeOut(5000);
            $(".container .photo.container", "#"+id).mousemove(function (){
                if($(".albums", "#"+id).is(":hidden") === true){
                    $(".albums", "#"+id).fadeIn(500);
                    $(".albums", "#"+id).stop().fadeTo(1, 1).fadeOut(10000); 
                }
            });
            $(".albums", "#"+id).on({
                mouseenter : function (){
                    $(this).stop().fadeTo(1, 1);
                },
                mouseout : function (){
                    $(this).fadeOut(5000);
                }
            });
            $(".albums img").click(function (){
                var loc = window.location;
                var currentURL = loc.protocol + '//' + loc.host + loc.pathname;
            });
        }
        //FINE EVENTI


        /*=================================
         * EVENTI DA TASTIERA
         ================================*/
        //if(!$.browser.device)
            $('body').on('keydown',function(e){
            });

            $('body').on('keypress',function(e){
            });

            $('body').on('keyup',function(e){
                if(e.keyCode === 39){//Freccia dx
                    pause();
                    next(); 
                }
                if(e.keyCode === 37){//Freccia sx
                    pause();
                    prev();
                }
            });
        //}
            //FINE EVENTI DA TASTIERA
        //}
        
        
        
        
        /**
         * Funzioni personali da applicare al plugin di jQuery per la fotogallery 
         */
    
         /**
          * Funzione per applicare il CSS a pagina intera della foto gallery
          * 
          * @returns Non ritorna nulla
          */
        function fullscreen(){
            
            //IMMAGGINI
            $("#"+id).css({
                'position' : 'fixed',
                'border' : '0px solid green',
                'width'  : '100%',
                'height' : '100%;'
            });
            //THUMBNAIL
            $(".container .thumbnail", "#"+id).css({
                'position'      : 'fixed',
                'bottom'        : '10px',
                'width'         : browser_screen_width+"px",
                'z-index'       : '99999',
            });
            //PUSHBUTTON
            $(".pushbutton", "#"+id).css({
                'position'      : 'fixed',
                'bottom'        : '76px',
                'left'          : (browser_screen_width-$(".pushbutton", "#"+id).width())/2,
                'z-index'       : '99999'
            });
            //ALBUMS
            $(".albums", "#"+id).css({
                'position' : 'absolute',
                'z-index'       : '99999',
                'width'         : browser_screen_width+"px"
            });

            //Mobile site
            if($.browser.device && browser_screen_width < 1024){
                $(".photo.container", "#"+id).css({
                    "margin-top"    : "200px",
                    "height"        : browser_screen_height-500+"px"
                });
                $(".photo.container img", "#"+id).css({
                    "height"        : "100%",
                    "margin-top"    : 0
                });
                $(".photo.container, .photo.container i.img, .photo.container .img img", "#"+id).css({
                    "width"         : "100%",
                });
                //ALBUMS
                $(".albums, .albums .img, .albums .img img", "#"+id).css({
                    "height" : "200px"
                });
                $(".albums .img, .albums .img img", "#"+id).css({
                    "width" : "200px"
                });
                //PUSHBUTTON
                $(".pushbutton", "#"+id).css({
                    "bottom"        : "230px",
                    "width"         : "600px",
                    "height"        : "100px",
                    "left"          : 0
                });
                $(".pushbutton .prev, .pushbutton .playpause, .pushbutton .next").css({
                    "width" : "200"
                });
                $(".pushbutton .prev img, .pushbutton .playpause img, .pushbutton .next img").css({
                    "width"     : "200px",
                    "height"    : "100px"
                });
                //THUMBNAIL
                $(".thumbnail, .thumbnail .img, .thumbnail .img img").css({
                    "height" : "200px",
                });
                $(".thumbnail .img, .thumbnail .img img").css({
                    "width" : "200px"
                });
            }
        }
        
        /**
         * Passa all'immagine successiva.
         * Se si arriva all'ultima immagine il puntatore punterà alla prima immagine.
         */
        function next(){
            var current = $(".photo.container .img.show", "#"+id);
            if(($(".photo.container .img", "#"+id).size()-1) > $(".photo.container .img", "#"+id).index(current)){
                current.hide().removeClass("show");
                current.next().addClass("show").fadeIn();
            }else{
                current.hide().removeClass("show");
                $(".container .photo.container .img:first-child", "#"+id).addClass("show").fadeIn();
            }
        }
        /**
         * Passa all'imagine precedente.
         * Se si arriva alla prima immagine il puntatore punterà all'ultima immagine.
         */
        function prev(){
            var current = $(".photo.container .img.show", "#"+id);
            if($(".photo.container .img", "#"+id).index(current) > 0){
                current.hide().removeClass("show");
                current.prev().addClass("show").fadeIn();
            }else{
                current.hide().removeClass("show");
                $(".container .photo.container .img:last-child", "#"+id).addClass("show").fadeIn();
            }
        }
        /**
         * Esegue automaticamente la fotogallery
         */
        function autoplay(){
            if(options.autoplay == true){
                var current = $(".container .photo.container .img.show", "#"+id);
                var next = (
                                $(".container .photo.container .img", "#"+id).index(current)
                                <
                                $(".container .photo.container .img", "#"+id).size()-1
                            ) ? (
                                current.next()
                            ) : (
                                $(".container .photo.container .img:first-child", "#"+id)
                            );

                current.hide();
                next.fadeIn();

                autoplay_timer = setTimeout(function (){
                    autoplay();

                    current.removeClass("show");
                    next.addClass("show");
                }, 3000);
            }
        }
        /**
         * Scambia le immagini di play e di pause sulla pulsantiera
         */
        function playorpause(){
            if(options.autoplay === true){
                $(".pushbutton .playpause img", "#"+id).remove();
                $(".pushbutton .playpause", "#"+id).append("<img src=\""+options.pushbutton['play']+"\" />");
                $(".pushbutton .playpause img", "#"+id).attr("style", $(".pushbutton .playpause", "#"+id).attr("style"));
                options.autoplay = false;
                clearTimeout(autoplay_timer);
            }else{
                $(".pushbutton .playpause img", "#"+id).remove();
                $(".pushbutton .playpause", "#"+id).append("<img src=\""+options.pushbutton['pause']+"\" />");
                $(".pushbutton .playpause img", "#"+id).attr("style", $(".pushbutton .playpause", "#"+id).attr("style"));
                options.autoplay = true;
                autoplay();
            }
        }
        /**
         * Mette in pause
         */
        function pause(){
            if(options.autoplay === true){
                $(".pushbutton .playpause img", "#"+id).remove();
                $(".pushbutton .playpause", "#"+id).append("<img src=\""+options.pushbutton['play']+"\" />");
                $(".pushbutton .playpause img", "#"+id).attr("style", $(".pushbutton .playpause", "#"+id).attr("style"));
                options.autoplay = false;
                clearTimeout(autoplay_timer);
            }
        }

        return this;//Permetto l'accodamento di altre funzioni
    };
})(jQuery);




/*
 * jQuery Event Mousestop v0.1.1
 * http://richardscarrott.co.uk/posts/view/jquery-mousestop-event
 *
 * Copyright (c) 2010 Richard Scarrott
 * W/ thanks to Ben Alman for his jQuery special event API write up:
 * http://benalman.com/news/2010/03/jquery-special-events/
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Requires jQuery v1.3+
 */

(function($) {
    // public vars
    $.mousestopDelay = 50;

    // special event
    $.event.special.mousestop = {
        setup: function(data) {
            $(this).data('mousestop', {delay: data})
                   .bind('mouseenter.mousestop', mouseenterHandler)
                   .bind('mouseleave.mousestop', mouseleaveHandler);
        },
        teardown: function() {
            $(this).removeData('mousestop')
                   .unbind('.mousestop');
        }
    };

    // private methods
    function mouseenterHandler() {
        if (typeof this.timeout === 'undefined') {
            this.timeout = null;
        }
        
        var elem = $(this),
            data = elem.data('mousestop'),
            delay = data.delay || $.mousestopDelay;

        elem.bind('mousemove.mousestop', function() {
            clearTimeout(this.timeout);
            this.timeout = setTimeout(function() {
                elem.trigger('mousestop');
                elem.unbind('mousemove.mousestop');
            }, delay);
        });
    };
    
    function mouseleaveHandler() {
        var elem = $(this);
        elem.unbind('mousemove.mousestop');
        clearTimeout(this.timeout);
    };

    // shorthand alias
    $.fn.mousestop = function(data, fn) {
        if (fn == null) {
            fn = data;
            data = null;
        }

        return arguments.length > 0 ? this.bind('mousestop', data, fn) : this.trigger('mousestop');
    };
})(jQuery);